// Serial.cpp

#define WIN32_LEAN_AND_MEAN		// Exclude rarely-used stuff from Windows headers
#include <windows.h>
//#include <stdio.h>
//#include <process.h>
//#include <conio.h>
#include "sioport.h"


HANDLE m_hIDComDev = NULL;
BOOL m_bOpened = FALSE;
OVERLAPPED m_OverlappedRead;
OVERLAPPED m_OverlappedWrite;


unsigned char IsOpened(void)
{
	return m_bOpened;
}

unsigned char Open(int nPort, int nBaud)
{
    char szPort[15];
    char szComParams[50];
    DCB dcb;
    COMMTIMEOUTS CommTimeOuts;
    unsigned char ucSet;

    if (m_bOpened)
        return TRUE;

    wsprintf(szPort, "COM%d", nPort);
    m_hIDComDev = CreateFile(szPort, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);

    if (m_hIDComDev == INVALID_HANDLE_VALUE)
        return FALSE;

    memset(&m_OverlappedRead, 0, sizeof(OVERLAPPED));
    memset(&m_OverlappedWrite, 0, sizeof(OVERLAPPED));

    CommTimeOuts.ReadIntervalTimeout = 0xFFFFFFFF;
    CommTimeOuts.ReadTotalTimeoutMultiplier = 0;
    CommTimeOuts.ReadTotalTimeoutConstant = 0;
    CommTimeOuts.WriteTotalTimeoutMultiplier = 0;
    CommTimeOuts.WriteTotalTimeoutConstant = 5000;
    SetCommTimeouts(m_hIDComDev, &CommTimeOuts);

    wsprintf(szComParams, "COM%d:%d,n,8,1", nPort, nBaud);

    m_OverlappedRead.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
    m_OverlappedWrite.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

    dcb.DCBlength = sizeof(DCB);
    GetCommState(m_hIDComDev, &dcb);
    dcb.BaudRate = nBaud;
    dcb.ByteSize = 8;
    dcb.Parity = 0;
    ucSet = (unsigned char)((FC_RTSCTS & FC_DTRDSR) != 0);
    ucSet = (unsigned char)((FC_RTSCTS & FC_RTSCTS) != 0);
    ucSet = (unsigned char)((FC_RTSCTS & FC_XONXOFF) != 0);
    if (!SetCommState(m_hIDComDev, &dcb) ||
        !SetupComm(m_hIDComDev, 10000, 10000) ||
        m_OverlappedRead.hEvent == NULL ||
        m_OverlappedWrite.hEvent == NULL)
    {
        DWORD dwError = GetLastError();
        if (m_OverlappedRead.hEvent != NULL)
            CloseHandle(m_OverlappedRead.hEvent);
        if (m_OverlappedWrite.hEvent != NULL)
            CloseHandle(m_OverlappedWrite.hEvent);
        CloseHandle(m_hIDComDev);
        return FALSE;
    }
    m_bOpened = TRUE;
    return m_bOpened;
}

unsigned char Close(void)
{
    if (!m_bOpened || m_hIDComDev == NULL)
        return TRUE;
    if (m_OverlappedRead.hEvent != NULL)
        CloseHandle(m_OverlappedRead.hEvent);
    if (m_OverlappedWrite.hEvent != NULL)
        CloseHandle(m_OverlappedWrite.hEvent);
    CloseHandle(m_hIDComDev);
    m_bOpened = FALSE;
    m_hIDComDev = NULL;
    return TRUE;
}

BOOL WriteCommByte(unsigned char ucByte)
{
    BOOL bWriteStat;
    DWORD dwBytesWritten;

    bWriteStat = WriteFile(m_hIDComDev, (LPSTR)&ucByte, 1, &dwBytesWritten, &m_OverlappedWrite);
    if (!bWriteStat && (GetLastError() == ERROR_IO_PENDING)) {
		if (WaitForSingleObject(m_OverlappedWrite.hEvent, 1000)) {
            dwBytesWritten = 0;
		} else {
            GetOverlappedResult(m_hIDComDev, &m_OverlappedWrite, &dwBytesWritten, FALSE);
            m_OverlappedWrite.Offset += dwBytesWritten;
        }
    }
    return TRUE;
}

int SendData(const char* buffer, int size)
{
    DWORD dwBytesWritten = 0;
    int i;

    if (!m_bOpened || m_hIDComDev == NULL)
        return 0 ;
    for (i = 0; i < size; i++) {
        WriteCommByte(buffer[i]);
        dwBytesWritten++;
    }
    return (int)dwBytesWritten;
}

int ReadDataWaiting(void)
{
    DWORD dwErrorFlags;
    COMSTAT ComStat;

    if (!m_bOpened || m_hIDComDev == NULL) 
        return 0 ;
    ClearCommError(m_hIDComDev, &dwErrorFlags, &ComStat);
    return (int)ComStat.cbInQue;
}

int ReadData(void* buffer, int limit)
{
    BOOL bReadStatus;
    DWORD dwBytesRead, dwErrorFlags;
    COMSTAT ComStat;

    if (!m_bOpened || m_hIDComDev == NULL) 
        return 0;
    ClearCommError(m_hIDComDev, &dwErrorFlags, &ComStat);
    if (!ComStat.cbInQue)
        return 0;
    dwBytesRead = (DWORD)ComStat.cbInQue;
    if (limit < (int)dwBytesRead)
        dwBytesRead = (DWORD)limit;
    bReadStatus = ReadFile(m_hIDComDev, buffer, dwBytesRead, &dwBytesRead, &m_OverlappedRead);
    if (!bReadStatus) {
        if (GetLastError() == ERROR_IO_PENDING) {
            WaitForSingleObject(m_OverlappedRead.hEvent, 2000);
            return (int)dwBytesRead;
        }
        return 0;
    }
    return (int)dwBytesRead;
}

